package com.icinema.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.icinema.client.Constants;
import com.icinema.client.Message;
import com.icinema.client.MovieService;
import com.icinema.server.builders.MovieDetailListBuilder;
import com.icinema.server.factories.EntityFactory;
import com.icinema.vo.Cinema;
import com.icinema.vo.Movie;
import com.icinema.vo.MovieDetail;
import com.icinema.vo.MovieShowing;
import com.icinema.vo.MovieShowingDetail;
import com.icinema.vo.Rating;

public class MovieServiceImpl extends RemoteServiceServlet implements MovieService {
	/**
	 * 
	 */
	private static final long serialVersionUID = 4471909838778367820L;
	DatastoreService datastore;

	
	public MovieServiceImpl(){
		datastore = DatastoreServiceFactory.getDatastoreService();
	}
	
	@Override
	public String addMovieShowing(MovieShowing movieShowing) {
		Entity movieShowingEntity = new Entity(MovieShowing.class.getSimpleName());
		movieShowingEntity.setProperty("cinemaId",movieShowing.getCinemaId());
		movieShowingEntity.setProperty("movieId",movieShowing.getMovieId());
		movieShowingEntity.setProperty("showingFromDate",movieShowing.getShowingFromDate());
		movieShowingEntity.setProperty("showingToDate",movieShowing.getShowingToDate());
		datastore.put(movieShowingEntity);		
		return KeyFactory.keyToString(movieShowingEntity.getKey());
	}

	@Override
	public List<MovieShowingDetail> getMovieShowings() {
		MovieDetailListBuilder movieDetailListBuilder = new MovieDetailListBuilder();
		movieDetailListBuilder.setDatastore(datastore);
		return movieDetailListBuilder.getMovieShowings();
	}
	@Override
	public List<MovieShowingDetail> getMovieShowings(int duration) {
		Query query = new Query(MovieShowing.class.getSimpleName());
		
		
		
		List<MovieShowing> results = new ArrayList<MovieShowing>();
		
		for(Entity entity : datastore.prepare(query).asIterable(FetchOptions.Builder.withDefaults())) {
			
			Calendar before2WeeksDate = Calendar.getInstance();
			before2WeeksDate.add(Calendar.WEEK_OF_MONTH, -2);
			Calendar thisMonthDate = Calendar.getInstance();
			thisMonthDate.set(Calendar.DAY_OF_MONTH,1);
			
			Calendar showingFromDate = Calendar.getInstance();
			showingFromDate.setTime(CommonUtils.getDate((String)entity.getProperty("showingFromDate")));
			
			MovieShowing movieShowing = new MovieShowing();
			movieShowing.setShowingFromDate((String)entity.getProperty("showingFromDate"));
			movieShowing.setShowingToDate((String)entity.getProperty("showingToDate"));
			movieShowing.setCinemaId((String)entity.getProperty("cinemaId"));
			movieShowing.setMovieId((String)entity.getProperty("movieId"));
			movieShowing.setId(KeyFactory.keyToString(entity.getKey()));
			results.add(movieShowing);

		}
		List<MovieShowingDetail> detailList = new ArrayList<MovieShowingDetail>();
		
		for(MovieShowing movieShowing:results){
			MovieShowingDetail detail = new MovieShowingDetail();
			detail.setMovieShowing(movieShowing);
			Entity movieEntity;
			try {
				movieEntity = datastore.get(KeyFactory.stringToKey(movieShowing.getMovieId()));
				Entity cinemaEntity = datastore.get(KeyFactory.stringToKey(movieShowing.getCinemaId()));
				detail.setMovie(fromMovieEntity(movieEntity));
				detail.setCinema(fromCinemaEntity(cinemaEntity));
				detailList.add(detail);
			} catch (EntityNotFoundException e) {
				e.printStackTrace();
			}			
		}
		
		return detailList;
	}	
	
	public void delete(String encodedKey) {
		Key key = KeyFactory.stringToKey(encodedKey);
		datastore.delete(key);
	}
	
	@Override
	public void deleteShowingMovie(String encodedKey) {
		Key key = KeyFactory.stringToKey(encodedKey);
		datastore.delete(key);
	}
	

	@Override
	public Message deleteMovie(String encodedKey) {
		Query query = new Query(MovieShowing.class.getSimpleName());
		query.addFilter("movieId", FilterOperator.EQUAL, encodedKey);
		Message msg = new Message();
		 if(datastore.prepare(query).asIterable(FetchOptions.Builder.withDefaults()).iterator().hasNext()){
			 msg.setErr_msg("This Movie is in the showing list.Cannot Delete");
			 return msg;
		 }
		 delete(encodedKey);
		 return msg;
	}

	@Override
	public String addMovie(String movieName,String ratingId) {
		Entity movieEntity = new Entity(Movie.class.getSimpleName());
		movieEntity.setProperty("name",movieName);
		movieEntity.setProperty("ratingId",ratingId);
		datastore.put(movieEntity);
		return KeyFactory.keyToString(movieEntity.getKey());
	}
	
	@Override
	public List<MovieDetail> getMovies() {
		Query query = new Query(Movie.class.getSimpleName());
		
		List<Movie> results = new ArrayList<Movie>();
		
		for(Entity entity : datastore.prepare(query).asIterable(FetchOptions.Builder.withDefaults())) {
			results.add(fromMovieEntity(entity));
		}
		List<MovieDetail> movieDetailList = new ArrayList<MovieDetail>();
		for(Movie movie:results){
			MovieDetail detail = new MovieDetail();
			try {
				Entity ratingEntity = datastore.get(KeyFactory.stringToKey(movie.getRatingId()));
				detail.setRating(fromRatingEntity(ratingEntity));
				detail.setMovie(movie);
				movieDetailList.add(detail);
			} catch (EntityNotFoundException e) {
				e.printStackTrace();
			}
		}
		return movieDetailList;
	}	
	
	public Rating fromRatingEntity(Entity entity){
		return new EntityFactory<Rating>().toRating(entity);
	}
	public Movie fromMovieEntity(Entity entity){
		return new EntityFactory<Movie>().toMovie(entity);
	}
	public Cinema fromCinemaEntity(Entity entity){
		return new EntityFactory<Cinema>().toCinema(entity);
	}
}
